package com.pioneer.cloudstorage.service.impl;

import com.pioneer.cloudstorage.utils.FileContentMapper;
import com.pioneer.cloudstorage.pojo.entity.FileContentIndex;
import com.pioneer.cloudstorage.pojo.entity.FileMetadata;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;

@Slf4j
@Service
public class FileIndexService {

    @Autowired
    private FileContentMapper fileContentRepository;

    @Autowired
    private FileContentParserService fileContentParserService;

    @Value("${file.upload.base-dir:./data/clouddisk}")
    private String baseUploadDir;

    @Value("${file.index.enabled:true}")
    private boolean indexEnabled;

    /**
     * 异步索引文件内容 - 本地文件存储版本
     */
    @Async
    public void asyncIndexFileContent(FileMetadata fileMetadata) {
        if (!indexEnabled) {
            log.info("文件内容索引功能已禁用，跳过索引: {}", fileMetadata.getFileName());
            return;
        }

        // 检查是否支持索引的文件类型
        if (!fileContentParserService.isIndexableType(fileMetadata.getMimeType())) {
            log.info("文件类型不支持内容索引: {}, MIME: {}",
                    fileMetadata.getFileName(), fileMetadata.getMimeType());
            return;
        }

        log.info("开始索引文件内容，文件ID: {}, 文件名: {}, 存储路径: {}",
                fileMetadata.getId(), fileMetadata.getFileName(), fileMetadata.getFilePath());

        FileContentIndex index = new FileContentIndex(
                fileMetadata.getId(),
                fileMetadata.getUserId(),
                fileMetadata.getFileName(),
                fileMetadata.getMimeType()
        );
        // 确保日期格式正确
        index.setIndexedTime(LocalDateTime.now());

        File physicalFile = getPhysicalFile(fileMetadata);
        if (physicalFile == null || !physicalFile.exists()) {
            log.error("物理文件不存在，无法索引: {}", fileMetadata.getFilePath());
            index.setContent("");
            index.setIndexedSuccess(false);
            fileContentRepository.save(index);
            return;
        }

        if (!physicalFile.canRead()) {
            log.error("物理文件不可读，无法索引: {}", physicalFile.getAbsolutePath());
            index.setContent("");
            index.setIndexedSuccess(false);
            fileContentRepository.save(index);
            return;
        }

        try (InputStream inputStream = new FileInputStream(physicalFile)) {

            // 解析文件内容
            String content = fileContentParserService.parseFileContent(
                    inputStream, fileMetadata.getMimeType(), fileMetadata.getFileName());

            if (content == null || content.trim().isEmpty()) {
                log.warn("文件内容为空或解析失败: {}", fileMetadata.getFileName());
                index.setContent("");
                index.setIndexedSuccess(false);
            } else {
                index.setContent(content);
                index.setIndexedSuccess(true);
                log.info("文件内容解析成功，长度: {} 字符, 文件: {}, 大小: {} bytes",
                        content.length(), fileMetadata.getFileName(), physicalFile.length());
            }

            // 保存到 Elasticsearch
            FileContentIndex savedIndex = fileContentRepository.save(index);
            log.info("文件内容索引完成，索引ID: {}, 文件ID: {}",
                    savedIndex.getId(), fileMetadata.getId());

        } catch (Exception e) {
            log.error("文件内容索引失败，文件ID: {}, 文件名: {}, 路径: {}",
                    fileMetadata.getId(), fileMetadata.getFileName(), fileMetadata.getFilePath(), e);

            // 记录索引失败
            index.setContent("");
            index.setIndexedSuccess(false);
            fileContentRepository.save(index);
        }
    }


    /**
     * 根据文件路径获取物理文件
     * 处理相对路径和绝对路径
     */
    private File getPhysicalFile(FileMetadata fileMetadata) {
        if (fileMetadata == null || fileMetadata.getFilePath() == null) {
            return null;
        }

        String filePath = fileMetadata.getFilePath();
        log.debug("解析文件路径: {}", filePath);

        // 方案1: 如果路径是绝对路径，直接使用
        File absoluteFile = new File(filePath);
        if (absoluteFile.isAbsolute()) {
            log.debug("使用绝对路径: {}", absoluteFile.getAbsolutePath());
            return absoluteFile;
        }

        // 方案2: 如果路径以 .\ 或 ./ 开头，可能是相对于项目根目录的路径
        if (filePath.startsWith(".\\") || filePath.startsWith("./")) {
            // 移除开头的 .\ 或 ./
            String relativePath = filePath.substring(2);
            File projectRelativeFile = new File(System.getProperty("user.dir"), relativePath);
            log.debug("项目相对路径解析: {} -> {}", filePath, projectRelativeFile.getAbsolutePath());

            if (projectRelativeFile.exists()) {
                return projectRelativeFile;
            }
        }

        // 方案3: 使用配置的基础目录
        if (baseUploadDir != null && !baseUploadDir.trim().isEmpty()) {
            File baseDir = new File(baseUploadDir);

            // 如果基础目录是相对路径，转换为绝对路径
            if (!baseDir.isAbsolute()) {
                baseDir = new File(System.getProperty("user.dir"), baseUploadDir);
            }

            File baseDirFile = new File(baseDir, filePath);
            log.debug("基础目录路径解析: {} + {} -> {}", baseDir.getAbsolutePath(), filePath, baseDirFile.getAbsolutePath());

            if (baseDirFile.exists()) {
                return baseDirFile;
            }
        }

        // 方案4: 直接在当前工作目录下查找
        File workingDirFile = new File(System.getProperty("user.dir"), filePath);
        log.debug("工作目录路径解析: {} -> {}", filePath, workingDirFile.getAbsolutePath());

        if (workingDirFile.exists()) {
            return workingDirFile;
        }

        // 方案5: 尝试各种可能的路径组合
        File[] possiblePaths = {
                new File(filePath), // 原始路径
                new File(System.getProperty("user.dir"), filePath), // 工作目录 + 原始路径
                new File("storage", filePath), // storage/ + 原始路径
                new File(baseUploadDir != null ? baseUploadDir : "storage", filePath) // 配置目录 + 原始路径
        };

        for (File possiblePath : possiblePaths) {
            if (possiblePath.exists()) {
                log.debug("找到文件路径: {}", possiblePath.getAbsolutePath());
                return possiblePath;
            }
        }

        log.warn("无法找到物理文件，尝试的路径:");
        log.warn("原始路径: {}", filePath);
        log.warn("工作目录路径: {}", new File(System.getProperty("user.dir"), filePath).getAbsolutePath());
        if (baseUploadDir != null) {
            log.warn("基础目录路径: {}", new File(baseUploadDir, filePath).getAbsolutePath());
        }

        return null;
    }


    /**
     * 检查文件是否存在且可读
     */
    private boolean isFileAccessible(File file) {
        return file != null && file.exists() && file.isFile() && file.canRead();
    }

    /**
     * 重新索引单个文件（用于修复索引）
     */
    @Async
    public void asyncReindexFile(Long fileId, FileMetadata fileMetadata) {
        log.info("重新索引文件，文件ID: {}", fileId);

        // 先删除旧索引
        asyncDeleteFileIndex(fileId);

        // 等待一小段时间确保删除完成
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // 创建新索引
        asyncIndexFileContent(fileMetadata);
    }

    /**
     * 批量索引用户文件（用于用户迁移或初始化）
     */
    @Async
    public void asyncBatchIndexUserFiles(Long userId, java.util.List<FileMetadata> fileMetadatas) {
        log.info("开始批量索引用户文件，用户ID: {}, 文件数量: {}", userId, fileMetadatas.size());

        int successCount = 0;
        int failCount = 0;

        for (FileMetadata fileMetadata : fileMetadatas) {
            if (!fileMetadata.getUserId().equals(userId)) {
                log.warn("文件用户ID不匹配，跳过: {}", fileMetadata.getId());
                continue;
            }

            try {
                asyncIndexFileContent(fileMetadata);
                successCount++;

                // 小延迟，避免对系统造成太大压力
                Thread.sleep(50);
            } catch (Exception e) {
                log.error("批量索引文件失败，文件ID: {}", fileMetadata.getId(), e);
                failCount++;
            }
        }

        log.info("批量索引完成，用户ID: {}, 成功: {}, 失败: {}", userId, successCount, failCount);
    }

    /**
     * 删除文件索引
     */
    @Async
    public void asyncDeleteFileIndex(Long fileId) {
        try {
            long count = fileContentRepository.count();
            log.debug("删除前索引总数: {}", count);

            fileContentRepository.deleteByFileId(fileId);
            log.info("删除文件索引成功，文件ID: {}", fileId);

            // 验证删除结果
            FileContentIndex remainingIndex = fileContentRepository.findByFileId(fileId);
            if (remainingIndex == null) {
                log.debug("文件索引删除验证成功，文件ID: {}", fileId);
            } else {
                log.warn("文件索引删除后仍存在，文件ID: {}", fileId);
            }
        } catch (Exception e) {
            log.error("删除文件索引失败，文件ID: {}", fileId, e);
        }
    }

    /**
     * 更新文件索引（当文件重命名时）
     */
    @Async
    public void asyncUpdateFileName(Long fileId, String newFileName) {
        try {
            FileContentIndex index = fileContentRepository.findByFileId(fileId);
            if (index != null) {
                index.setFileName(newFileName);
                fileContentRepository.save(index);
                log.info("更新文件名索引成功，文件ID: {}, 新文件名: {}", fileId, newFileName);
            } else {
                log.info("文件索引不存在，无法更新文件名，文件ID: {}", fileId);
            }
        } catch (Exception e) {
            log.error("更新文件名索引失败，文件ID: {}", fileId, e);
        }
    }

    /**
     * 获取文件索引状态
     */
    public FileIndexStatus getFileIndexStatus(Long fileId) {
        try {
            FileContentIndex index = fileContentRepository.findByFileId(fileId);
            if (index == null) {
                return new FileIndexStatus(fileId, false, "未索引");
            }

            return new FileIndexStatus(
                    fileId,
                    index.getIndexedSuccess(),
                    index.getIndexedSuccess() ? "索引成功" : "索引失败"
            );
        } catch (Exception e) {
            log.error("获取文件索引状态失败，文件ID: {}", fileId, e);
            return new FileIndexStatus(fileId, false, "查询失败");
        }
    }

    /**
     * 索引状态内部类
     */
    public static class FileIndexStatus {
        private Long fileId;
        private boolean indexed;
        private String status;

        public FileIndexStatus(Long fileId, boolean indexed, String status) {
            this.fileId = fileId;
            this.indexed = indexed;
            this.status = status;
        }

        // getter and setter
        public Long getFileId() { return fileId; }
        public void setFileId(Long fileId) { this.fileId = fileId; }
        public boolean isIndexed() { return indexed; }
        public void setIndexed(boolean indexed) { this.indexed = indexed; }
        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }
    }
}
